/* Copyright (c) 2022 渝州大数据实验室
 *
 * Lanius is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *
 *     http://license.coscl.org.cn/MulanPSL2
 *
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 */
package org.yzbdl.lanius.orchestrate.serv.service.resource.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.yzbdl.lanius.orchestrate.common.constant.Const;
import org.yzbdl.lanius.orchestrate.common.dto.resource.TaskResourceGroupCountDto;
import org.yzbdl.lanius.orchestrate.common.dto.resource.TaskResourceTreeDto;
import org.yzbdl.lanius.orchestrate.common.entity.resource.TaskResourceEntity;
import org.yzbdl.lanius.orchestrate.common.entity.resource.TaskResourceGroupEntity;
import org.yzbdl.lanius.orchestrate.common.exception.runtime.BusinessException;
import org.yzbdl.lanius.orchestrate.common.utils.ExceptionUtil;
import org.yzbdl.lanius.orchestrate.serv.mapper.resource.TaskResourceGroupMapper;
import org.yzbdl.lanius.orchestrate.serv.mapper.resource.TaskResourceMapper;
import org.yzbdl.lanius.orchestrate.serv.service.resource.TaskResourceGroupService;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author zhuhongji@yzbdl.ac.cn
 * @date 2022-04-11 11:30
 */
@Service
@AllArgsConstructor
public class TaskResourceGroupServiceImpl extends ServiceImpl<TaskResourceGroupMapper, TaskResourceGroupEntity> implements TaskResourceGroupService {

	private final TaskResourceMapper taskResourceMapper;

	@Override
	public List<TaskResourceTreeDto> buildResourceTree(){
		// 获取原始数据
		LambdaQueryWrapper<TaskResourceGroupEntity> queryWrapper = new QueryWrapper<TaskResourceGroupEntity>().lambda()
				.eq(TaskResourceGroupEntity::getDeleted, false);
		List<TaskResourceGroupEntity> groupList = this.list(queryWrapper);
		// 获取分组数量信息
		List<TaskResourceGroupCountDto> resourceCounts = taskResourceMapper.getResourceCount();
		Map<Long, Integer> countMap = resourceCounts.stream().collect(Collectors
				.toMap(TaskResourceGroupCountDto::getGroupId, TaskResourceGroupCountDto::getCount));

		// 增加了根节点，需要特殊处理
		// 构建树节点
		List<TaskResourceTreeDto> treeNodes = groupList.stream()
				.map(g -> TaskResourceTreeDto.builder().id(g.getId())
						.parentId(Optional.ofNullable(g.getPid())
								.orElse(Const.TaskResourceGroup.TASK_RESOURCE_GROUP_ROOT_NODE_ID))
						.groupName(g.getGroupName())
						.count(Optional.ofNullable(countMap.get(g.getId())).orElse(0)).build())
				.collect(Collectors.toList());

		// 计算所有分组的资源总数
		int totalCount = resourceCounts.stream().mapToInt(TaskResourceGroupCountDto::getCount).sum();

		// 手动创建根节点，放入list首位
		TaskResourceTreeDto rootNode = TaskResourceTreeDto.builder()
				.id(Const.TaskResourceGroup.TASK_RESOURCE_GROUP_ROOT_NODE_ID)
				.parentId(null)
				.groupName(Const.TaskResourceGroup.TASK_RESOURCE_GROUP_ROOT_NODE_NAME)
				.count(totalCount)
				.build();
		treeNodes.add(0, rootNode);

		return buildTree(treeNodes);
	}

	@Override
	public Boolean addTaskResourceGroup(TaskResourceGroupEntity taskResourceGroupEntity) {
		// 重命名判断
		LambdaQueryWrapper<TaskResourceGroupEntity> queryWrapper = new QueryWrapper<TaskResourceGroupEntity>().lambda()
				.eq(TaskResourceGroupEntity::getGroupName, taskResourceGroupEntity.getGroupName())
				.eq(TaskResourceGroupEntity::getDeleted, false);
		ExceptionUtil.checkParam(!this.baseMapper.exists(queryWrapper), "已存在同样的分组节点名，请重新输入！");
		// 层级判断
		Long pid = taskResourceGroupEntity.getPid();
		if (Objects.nonNull(pid)){
			List<TaskResourceGroupEntity> parents = this.baseMapper.getParentsById(pid);
			if (!CollectionUtils.isEmpty(parents) && parents.size() > 4){
				throw new BusinessException("分组最多5层！");
			}
		}
		taskResourceGroupEntity.setDeleted(false);
		return this.save(taskResourceGroupEntity);
	}

	@Override
	public Boolean updateTaskResourceGroup(TaskResourceGroupEntity taskResourceGroupEntity) {
		ExceptionUtil.checkParam(Objects.nonNull(taskResourceGroupEntity.getId()), "请输入数据id！");
		// 重命名判断
		LambdaQueryWrapper<TaskResourceGroupEntity> queryWrapper = new QueryWrapper<TaskResourceGroupEntity>().lambda()
				.ne(TaskResourceGroupEntity::getId, taskResourceGroupEntity.getId())
				.eq(TaskResourceGroupEntity::getGroupName, taskResourceGroupEntity.getGroupName())
				.eq(TaskResourceGroupEntity::getDeleted, false);
		ExceptionUtil.checkParam(!this.baseMapper.exists(queryWrapper), "已存在同样的分组节点名，请重新输入！");
		return this.updateById(taskResourceGroupEntity);
	}

	@Override
	public Boolean deleteTaskResourceGroup(Long id) {
		LambdaQueryWrapper<TaskResourceEntity> queryWrapper = new QueryWrapper<TaskResourceEntity>().lambda()
				.eq(TaskResourceEntity::getGroupId, id)
				.eq(TaskResourceEntity::getDeleted, false);
		// 判断当前目录是否存在内容
		ExceptionUtil.checkParam(!taskResourceMapper.exists(queryWrapper), "请删除当前目录下的任务资源！");
		LambdaQueryWrapper<TaskResourceGroupEntity> groupQueryWrapper = new QueryWrapper<TaskResourceGroupEntity>().lambda()
				.eq(TaskResourceGroupEntity::getPid, id)
				.eq(TaskResourceGroupEntity::getDeleted, false);
		// 判断当前目录是否存在子目录
		ExceptionUtil.checkParam(!this.baseMapper.exists(groupQueryWrapper), "请删除当前目录下的子目录！");
		return this.updateById(TaskResourceGroupEntity.builder().id(id).deleted(true).build());
	}

	@Override
	public Boolean directlyDeleteTaskResourceGroup(Long id){
		return this.updateById(TaskResourceGroupEntity.builder().id(id).deleted(true).build());
	}

	@Override
	public Boolean isExistChildrenTaskResourceGroup(Long id) {
		LambdaQueryWrapper<TaskResourceGroupEntity> groupQueryWrapper = new QueryWrapper<TaskResourceGroupEntity>().lambda()
				.eq(TaskResourceGroupEntity::getPid, id)
				.eq(TaskResourceGroupEntity::getDeleted, false);
		// 判断当前目录是否存在子目录
		return this.baseMapper.exists(groupQueryWrapper);
	}

	@Override
	public TaskResourceGroupEntity getTaskResourceGroup(Long id) {
		return this.getById(id);
	}

	@Override
	public List<TaskResourceGroupEntity> getTaskResourceGroup(String groupName) {
		if(!StringUtils.hasLength(groupName)) {return new ArrayList<>();}
		// 获取原始数据
		LambdaQueryWrapper<TaskResourceGroupEntity> queryWrapper = new QueryWrapper<TaskResourceGroupEntity>().lambda()
				.like(TaskResourceGroupEntity::getGroupName, groupName)
				.eq(TaskResourceGroupEntity::getDeleted, false);
		return this.list(queryWrapper);
	}

	@Override
	public List<TaskResourceTreeDto> treeListForTaskPlan() {

		LambdaQueryWrapper<TaskResourceGroupEntity> queryWrapper = new QueryWrapper<TaskResourceGroupEntity>().lambda()
				.eq(TaskResourceGroupEntity::getDeleted, false);
		List<TaskResourceGroupEntity> groupList = this.list(queryWrapper);

		// 获取分组数量信息
		List<TaskResourceGroupCountDto> resourceCounts = taskResourceMapper.getResourceCount();
		Map<Long, Integer> countMap = resourceCounts.stream().collect(Collectors
				.toMap(TaskResourceGroupCountDto::getGroupId, TaskResourceGroupCountDto::getCount));

		// 构建树节点
		List<TaskResourceTreeDto> treeNodes = groupList.stream()
				.map(g -> TaskResourceTreeDto.builder()
				.id(g.getId())
				.parentId(g.getPid())
				.groupName(g.getGroupName())
				.count(Optional.ofNullable(countMap.get(g.getId())).orElse(0))
				.build())
				.collect(Collectors.toList());
		return buildTree(treeNodes);
	}

	/**
	 * 递归构建带有树路径的节点
	 * @param treeNodes 节点合集
	 * @return 树结构
	 */
    private static List<TaskResourceTreeDto> buildTree(List<TaskResourceTreeDto> treeNodes) {
        return treeNodes.stream().filter(n -> Objects.isNull(n.getParentId())).peek(node -> {
	        node.setLevel(1);
            buildTreeChildren(treeNodes, node);
        }).collect(Collectors.toList());
    }

	/**
	 * 构建子节点
	 * @param treeNodes 节点合集
	 * @param parent 父节点
	 */
	private static void buildTreeChildren(List<TaskResourceTreeDto> treeNodes, TaskResourceTreeDto parent) {
		// 添加子节点
		treeNodes.stream().filter(n -> parent.getId().equals(n.getParentId())).forEach(node -> {
			node.setLevel(parent.getLevel() + 1);
			parent.addTreeNode(node);
		});
		// 值节点递归调用
		if (!CollectionUtils.isEmpty(parent.getChildren())) {
			parent.getChildren().forEach(node -> buildTreeChildren(treeNodes, node));
		}
	}

}
